#include <CGamer.h>

/*
void createWindingNumbers() {
  int cnt  = 0;
 
 for (int i=1;i<10;i++) {
    for (int j = 1;j<10;j++) {
      g.params.windingB = 0.05*i;
      g.params.windingN = 2*j*pow(g.params.windingB, 1.0);
      g.RenderGalaxy(g.params.size, "galaxy.bmp");
      string fname = "windings2/wb" + CUtil::zeroPadd(cnt) + "_" + CUtil::toString(g.params.windingB) + "_wn" + CUtil::toString(g.params.windingN) + ".fits";
      g.image.SaveFits(fname,"leuats superfits");
      cnt++;
 
      
    }
  }

}
*/


void CGamer::createPerlinNoiseImages(int component) {
  C2DImage img;
  int N = 1024;
  img.Create(N,N);
  CGalaxyComponent* cs=  rasterizer.galaxies[0]->components[component];
  for (int i=0;i<N;i++)
    for (int j=0;j<N;j++) {

      double s = 0.5;
      double x = s*i/(double)N;
      double y = s*j/(double)N;


      /*      CVector p(x+0.1,y+0.1,0);

      float level = 16;
      


      float perlinnoise = 0;
      //10
      CVector r = p;
      for (int ii=1;ii<25;ii++) {
	float k= ii*7 + 5;
	float pp = abs(cs->perlin->Get( (r.x + cs->params->randShiftX*39.4)*k, (r.y+cs->params->randShiftY*59.1)*k, (r.z  + cs->params->randShiftY*(99.0))*k ));///pow(ii,0.25);
	perlinnoise+=pp;
      }
      perlinnoise-=0;
      if (perlinnoise<0) perlinnoise = 0;
      float val = 0.05*pow(perlinnoise,8);
*/
      double I = 0;
      CVector p(x-0.5*s,y-0.5*s,0);
      double val = cs->calculateIntensity(I, p, 1.0);


      img.Get(i,j)->height = val*2.5;
      

    }

  CBitMap bmp;
  img.ToBitMap(bmp, CVector(1,1,1));
  bmp.SaveBMP("Perlin.bmp");
  
}

void CGamer::Render(bool color, string name) {
  rasterizer.Prepare();

  if (rank == 0) {
    rasterizer.Master();
  }
  else 
    rasterizer.Slave();
}
    
void CGamer::RenderScene(bool color, string filename) {
  rasterizer.LoadRenderlist(filename);
  Render(color, "test");
}

void CGamer::RenderRandomScene(int N, double W) {
  
  for (int i=0;i<N;i++) {
    
    
    int gal = rand()%4 +1;
    //gal = 4;
    //gal = 3;
    string name = "galaxies/";
    if (gal<=1) 
      name = name + "E0.gax";
    if (gal==2) 
      name = name + "SAb.gax";
    if (gal==3) 
      name = name + "SB0.gax";
    if (gal==4) 
      name = name + "sombrero.gax";
    
    // fwhm = 20;
    CVector orientation = CVector(1,1,1);
    orientation = orientation.RandomUniform().Normalize();
    //cout << orientation << endl;
    //orientation = CVector(1,-1,-0.5).Normalize();

    CVector position = CVector(W,W,W);
    position = position.RandomUniform();
    //position.Set(0,0,0);
    
    CGalaxy* g = rasterizer.AddGalaxy(name, position, orientation, 0.1 + rand()%1500/1000.0);
    for (int i=0;i<g->spectra.size();i++) {
      float w = 0.85 + rand()%300/1000.0;
      g->spectra[i]->scaleX(w);
    }

    if (gal<=1) {
      g->params.bulgeAxis.y+=rand()%1000/1000.0;
    }
    
    if (gal==2 || gal==3) {
      g->params.arm2 = 3.1415 + (rand()%1000/1000.0 - 0.5);
      // random placement of arms
    }
  }
  Render(true, "test.fits");  
  
}


void CGamer::RenderRandomGalaxy() {

  CGraph FWHM;
  FWHM.LoadText("spectra/FWHM.lis");
  FWHM.Scale(1);
  double fwhm = FWHM.getRandomValue();
  int gal = rand()%5;
  //gal = 4;
  string name = "galaxies/";
  if (gal<=1) 
    name = name + "E0.gax";
  if (gal==2) 
    name = name + "SAb.gax";
  if (gal==3) 
    name = name + "SB0.gax";
  if (gal==4) 
    name = name + "sombrero.gax";

  if (rank==0) {
    cout <<"Galaxy selected " << name << endl;
    cout <<"FWHM selected " << fwhm << endl;
  

  }
  // fwhm = 20;
  CVector orientation = CVector(1,1,1);
  orientation = orientation.RandomUniform().Normalize();
  //cout << orientation << endl;
  //orientation = CVector(1,-1,-0.5).Normalize();
  float z = rasterizer.getZfromFWHM(CVector(0,0,0), fwhm);
  cout << "Random galaxy with z = " << z << endl;
  CGalaxy* g = rasterizer.AddGalaxy(name, CVector(0.0,0,z), orientation, 1.0);
  if (gal==2 || gal==3) {
    g->params.arm2 = 2.1415 + (rand()%1000/1000.0 - 0.5);
    // random placement of arms
  }


  // if elliptical, random bulge stretch
  if (gal<=1) {
    g->params.bulgeAxis.y+=rand()%1000/2000.0;
  }


  Render(false, "test.fits");  

  if (rank==0) {

    rasterizer.image.Convolve(0.0010);



    rasterizer.image.Normalize(1);
    //    rasterizer.image.Pow(0.85);
    rasterizer.image.AddNoise(0.005, false);
    rasterizer.image.Normalize(1);
    //cout <<"Saving fits" << endl;
    //rasterizer.image.SaveFits("test.fits","leuats superfits");
  }
}


void CGamer::printAscii() {

  string fname = "ascii.txt";
  fstream f(fname.c_str(), ios::in);
  int i = 0;
  char s[2000];
    while(!f.eof()) {
      f.getline(s,2000);
      string str = s;
      if (i++<20)
	cout <<  str << endl;
      else {
	if (i % 2 == 0)
	  cout <<  str << endl;
      }
    }
    f.close();

}


void CGamer::Initialize(int argc, char *argv[]) {
 
   // Wrapper: loads ini file and initialized all
  MPI::Init();
  rank = MPI::COMM_WORLD.Get_rank();
  no_procs = MPI::COMM_WORLD.Get_size();

  MPI::COMM_WORLD.Set_errhandler(MPI::ERRORS_THROW_EXCEPTIONS);
  if ( argc != 6 ) {
    cout << "Usage: gamer [rendering parameter file] [render list] [image size] [wavelength] [output filename]" << endl;
    MPI::Finalize();
    exit(1);
  }

  

  if (rank==0) {
    cout << "Number of processors: " << no_procs << endl;
    if (no_procs == 1) {
      cout << "Must use at least 2 processors" << endl;
      MPI::Finalize();
      exit(1);
    }
  }

  /*  if (rank==0) {
    printAscii();
  }
  */
  try {
    rasterizer.RP.loadFromIni(string(argv[1]));
    

    if (rasterizer.RP.seed==-1) {
      rasterizer.RP.seed = time(NULL);
      //seed = 0;
      srand(rasterizer.RP.seed);
    }
    else
      srand(rasterizer.RP.seed);

    rasterizer.loadSpectra();
    // cout <<"Done " << endl;
    
    rasterizer.RP.size = strtod ( argv[3],0);
    rasterizer.RP.wavelength = strtod (argv[4],0);
    filename = string(argv[5]);

    rasterizer.setupLensPlane();

    
    rasterizer.RP.no_procs = no_procs;
    rasterizer.RP.rank = rank;
    rasterizer.RP.perlin = new Perlin(6,1.0,1.0,rasterizer.RP.seed);
    srand(rasterizer.RP.seed);

    if (string(argv[2])=="random") 
      RenderRandomGalaxy();
    else
      RenderScene(0, string(argv[2]));
    //RenderRandomScene(10000, 150);


    if (rank == 0) {
      cout << "Saving fits" << endl;

      //      rasterizer.image.Convolve(0.0010, 0.0050);
      //      rasterizer.image.Convolve(0.0010);

      
      rasterizer.image.SaveFits(filename,"");
      
      struct tm *timeval;
      time_t tt;
      tt = time( NULL );
      timeval = localtime( &tt );
      if (timeval->tm_wday==5 && rank==0)
	rasterizer.image.PrintASCII();

    }
      
  } catch (string s) {
    cout << s<< endl;
    exit(1);
  }
  
  
  MPI::Finalize();
}
